using System.Buffers;
using System.Collections.Concurrent;
using System.Net;
using System.Net.Sockets;
using Nova.Net;
using System.Threading.Tasks;
using BufferOwner = System.Buffers.IMemoryOwner<byte>;

namespace KCP.Simple;

public class KcpServer
{
    private readonly UdpClient _client;
    private readonly ConcurrentDictionary<string, KcpSession> _sessions = new();
    private HashSet<uint> _convSet = new();
    private readonly Random _random = new Random();


    public delegate void OnOpenHandler(KcpSession session);
    public delegate void OnMessageHandler(KcpSession session, byte[] msg);

    public OnOpenHandler OnOpen;

    public OnMessageHandler OnMessage;

    public KcpServer(ushort port)
    {
        _client = new UdpClient(port);
        BeginRecvRaw();
        LoopUpdate();
        ConsumeRawQueue();
    }

    private void LoopUpdate()
    {
        Console.WriteLine("--Loop--");
        Task.Run(async () =>
        {
            while (true)
            {
                foreach (var kv in _sessions)
                {
                    kv.Value.kcp.Update(DateTimeOffset.UtcNow);
                }
                await Task.Delay(10);
            }
        });
    }


    private async void BeginRecvRaw()
    {
        Console.WriteLine("--BeginRecvRaw--");
        var res = await _client.ReceiveAsync();
        var session = makeSession(res.RemoteEndPoint);

        var pack = new DataPack
        {
            session = session,
            data = res.Buffer
        };
        rawQueue.Add(pack); // 将数据包添加到队列中，并通知消费者执行
        
        BeginRecvRaw();
    }
    
    private BlockingCollection<DataPack> rawQueue = new ();
    
    private async Task ConsumeRawQueue()
    {
        foreach (var pack in rawQueue.GetConsumingEnumerable())
        {
            // 执行消息处理逻辑
            Console.WriteLine($"Received data: {pack.data.Length}");
            PackHandle(pack);
        }
    }

    private void PackHandle(DataPack pack)
    {
        var session = pack.session;
        if (pack.data.Length == 6)
        {
            using var ds = DataStream.Allocate(pack.data);
            var action = ds.ReadUShort();
            var conv = ds.ReadUInt();
            Console.WriteLine($"action={action},conv={conv}");
            switch (action)
            {
                //客户端请求conv
                case 101:
                    //发送conv给客户端
                    send_conv_msg(session, 102);
                    return;
                case 103 when conv == session.kcp.conv:
                    Console.WriteLine($"Session已确认：conv={session.kcp.conv}");
                    session.state = 1;
                    return;
            }
        }

        session.RecvInput(pack.data);
    }


    private KcpSession makeSession(IPEndPoint remoteEndPoint)
    {
        string key = remoteEndPoint.ToString();
        Console.WriteLine($"SessionKey={key}");
        if (!_sessions.TryGetValue(key, out var session))
        {
            uint conv = GetNextConv();
            session = new KcpSession() { endPoint = remoteEndPoint, client = _client, Server = this};
            session.kcp = new SimpleSegManager.Kcp(conv, session);
            _sessions[key] = session;
        }

        return session;
    }

    /// <summary>
    /// 向客户端发送
    /// </summary>
    /// <param name="endPoint"></param>
    /// <param name="conv"></param>
    private async void send_conv_msg(KcpSession session, ushort action)
    {
        using var ds = DataStream.Allocate();
        ds.WriteUShort(action); //向客户端发送conv
        ds.WriteUInt(session.kcp.conv);
        _client.SendAsync(ds.ToArray(), (int)ds.Length, session.endPoint);
    }
    

    private uint GetNextConv()
    {
        lock (this)
        {
            uint conv;
            do
            {
                conv = (uint)_random.Next();
            } while (_convSet.Contains(conv));
            Console.WriteLine($"新的conv={conv}");
            return conv;
        }
    }
}

public class DataPack
{
    public KcpSession session;
    public byte[] data;
}